<?php
namespace Org\Util;
class Tree {
	/**
	 * 生成树型结构所需要的2维数组
	 * @var array
	 */
	public $arr = array ();
	
	/**
	 * 生成树型结构所需修饰符号，可以换成图片
	 * @var array
	 */
	public $icon = array ('│', '├', '└' );
	public $nbsp = "&nbsp;";
	
	/**
	 * @access private
	 */
	public $ret = '';
	
	/**
	 * 构造函数，初始化类
	 * @param array 2维数组，例如：
	 * array(
	 * 1 => array('id'=>'1','parentid'=>0,'name'=>'一级栏目一'),
	 * 2 => array('id'=>'2','parentid'=>0,'name'=>'一级栏目二'),
	 * 3 => array('id'=>'3','parentid'=>1,'name'=>'二级栏目一'),
	 * 4 => array('id'=>'4','parentid'=>1,'name'=>'二级栏目二'),
	 * 5 => array('id'=>'5','parentid'=>2,'name'=>'二级栏目三'),
	 * 6 => array('id'=>'6','parentid'=>3,'name'=>'三级栏目一'),
	 * 7 => array('id'=>'7','parentid'=>3,'name'=>'三级栏目二')
	 * )
	 */
	public function __construct($arr = array()) {
		$this->arr = $arr;
		$this->ret = '';
		return is_array ( $arr );
	}
	
	/**
	 * 得到父级数组
	 * @param int
	 * @return array
	 */
	public function get_parent($myid) {
		$newarr = array ();
		if (! isset ( $this->arr [$myid] )) {
			return false;
		}
		$pid = $this->arr [$myid] ['parentid'];
		$pid = $this->arr [$pid] ['parentid'];
		if (is_array ( $this->arr )) {
			foreach ( $this->arr as $id => $a ) {
				if ($a ['parentid'] == $pid) {
					$newarr [$id] = $a;
				}
			}
		}
		return $newarr;
	}
	
	/**
	 * 得到子级数组
	 * @param int
	 * @return array
	 */
	public function get_child($myid) {
		$a = $newarr = array ();
		if (is_array ( $this->arr )) {
			foreach ( $this->arr as $id => $a ) {
				if ($a ['parentid'] == $myid) {
					$newarr [$id] = $a;
				}
			}
		}
		return $newarr ? $newarr : false;
	}
	
	/**
	 * 得到当前位置数组
	 * @param int
	 * @return array
	 */
	public function get_pos($myid, &$newarr) {
		$a = array ();
		if (! isset ( $this->arr [$myid] )) {
			return false;
		}
		$newarr [] = $this->arr [$myid];
		$pid = $this->arr [$myid] ['parentid'];
		if (isset ( $this->arr [$pid] )) {
			$this->get_pos ( $pid, $newarr );
		}
		if (is_array ( $newarr )) {
			krsort ( $newarr );
			foreach ( $newarr as $v ) {
				$a [$v ['id']] = $v;
			}
		}
		return $a;
	}
	
	/**
	 * 得到树型结构
	 * @param int ID，表示获得这个ID下的所有子级
	 * @param string 生成树型结构的基本代码，例如："<option value=\$id \$selected>\$spacer\$name</option>"
	 * @param int 被选中的ID，比如在做树型下拉框的时候需要用到
	 * @return string
	 */
	public function get_tree($myid, $str, $sid = 0, $adds = '', $str_group = '') {
		$number = 1;
		$child = $this->get_child ( $myid );
		if (is_array ( $child )) {
			$total = count ( $child );
			foreach ( $child as $id => $value ) {
				$j = $k = '';
				if ($number == $total) {
					$j .= $this->icon [2];
				} else {
					$j .= $this->icon [1];
					$k = $adds ? $this->icon [0] : '';
				}
				$spacer = $adds ? $adds . $j : '';
				$selected = $id == $sid ? 'selected' : '';
				@extract ( $value );
				($parentid == 0) && $str_group ? eval ( "\$nstr = \"$str_group\";" ) : eval ( "\$nstr = \"$str\";" );
				$this->ret .= $nstr;
				$nbsp = $this->nbsp;
				$this->get_tree ( $id, $str, $sid, $adds . $k . $nbsp, $str_group );
				$number ++;
			}
		}
		return $this->ret;
	}
	
	/**
	 * 同上一方法类似,但允许多选
	 * @access public
	 */
	public function get_tree_multi($myid, $str, $sid = 0, $adds = '') {
		$number = 1;
		$child = $this->get_child ( $myid );
		if (is_array ( $child )) {
			$total = count ( $child );
			foreach ( $child as $id => $a ) {
				$j = $k = '';
				if ($number == $total) {
					$j .= $this->icon [2];
				} else {
					$j .= $this->icon [1];
					$k = $adds ? $this->icon [0] : '';
				}
				$spacer = $adds ? $adds . $j : '';
				
				$selected = $this->have ( $sid, $id ) ? 'selected' : '';
				@extract ( $a );
				eval ( "\$nstr = \"$str\";" );
				$this->ret .= $nstr;
				$this->get_tree_multi ( $id, $str, $sid, $adds . $k . '&nbsp;' );
				$number ++;
			}
		}
		return $this->ret;
	}
	
	/**
	 * @param integer $myid 要查询的ID
	 * @param string $str   第一种HTML代码方式
	 * @param string $str2  第二种HTML代码方式
	 * @param integer $sid  默认选中
	 * @param integer $adds 前缀
	 */
	public function get_tree_category($myid, $str, $str2, $sid = 0, $adds = '') {
		$number = 1;
		$child = $this->get_child ( $myid );
		if (is_array ( $child )) {
			$total = count ( $child );
			foreach ( $child as $id => $a ) {
				$j = $k = '';
				if ($number == $total) {
					$j .= $this->icon [2];
				} else {
					$j .= $this->icon [1];
					$k = $adds ? $this->icon [0] : '';
				}
				$spacer = $adds ? $adds . $j : '';
				
				$selected = $this->have ( $sid, $id ) ? 'selected' : '';
				@extract ( $a );
				if (empty ( $html_disabled )) {
					eval ( "\$nstr = \"$str\";" );
				} else {
					eval ( "\$nstr = \"$str2\";" );
				}
				$this->ret .= $nstr;
				$this->get_tree_category ( $id, $str, $str2, $sid, $adds . $k . '&nbsp;' );
				$number ++;
			}
		}
		return $this->ret;
	}
	
	/**
	 * 同上一类方法，jquery treeview 风格，可伸缩样式（需要treeview插件支持）
	 * @param $myid 表示获得这个ID下的所有子级
	 * @param $effected_id 需要生成treeview目录数的id
	 * @param $str 末级样式
	 * @param $str2 目录级别样式
	 * @param $showlevel 直接显示层级数，其余为异步显示，0为全部限制
	 * @param $style 目录样式 默认 filetree 可增加其他样式如'filetree treeview-famfamfam'
	 * @param $currentlevel 计算当前层级，递归使用 适用改函数时不需要用该参数
	 * @param $recursion 递归使用 外部调用时为FALSE
	 */
	public function get_treeview($myid, $effected_id = 'example', $str = "<span class='file'>\$name</span>", $str2 = "<span class='folder'>\$name</span>", $showlevel = 0, $style = 'filetree ', $currentlevel = 1, $recursion = FALSE) {
		$child = $this->get_child ( $myid );
		if (! defined ( 'EFFECTED_INIT' )) {
			$effected = ' id="' . $effected_id . '"';
			define ( 'EFFECTED_INIT', 1 );
		} else {
			$effected = '';
		}
		$placeholder = '<ul><li><span class="placeholder"></span></li></ul>';
		if (! $recursion) {
			$this->str .= '<ul' . $effected . '  class="' . $style . '">';
		}
		foreach ( $child as $id => $a ) {
			@extract ( $a );
			if ($showlevel > 0 && $showlevel == $currentlevel && $this->get_child ( $id )) {
				$folder = 'hasChildren'; // 如设置显示层级模式@2011.07.01
			}
			$floder_status = isset ( $folder ) ? ' class="' . $folder . '"' : '';
			$this->str .= $recursion ? '<ul><li' . $floder_status . ' id=\'' . $id . '\'>' : '<li' . $floder_status . ' id=\'' . $id . '\'>';
			$recursion = FALSE;
			if ($this->get_child ( $id )) {
				$str3 = "<img src='" . IMG_URL . "folder.gif'> <a href='?m=Admin&c=Content&a=\$type&menuid=" . $_GET ['menuid'] . "&catid=\$id' target='right' onclick='open_list(this)'>\$catname</a>";
				// 单页,碎片情况下,点击栏目就是执行页面,而非折叠.
				if ($type == 'add') {
					eval ( "\$nstr = \"$str3\";" );
				} else {
					eval ( "\$nstr = \"$str2\";" );
				}
				
				$this->str .= $nstr;
				if ($showlevel == 0 || ($showlevel > 0 && $showlevel > $currentlevel)) {
					$this->get_treeview ( $id, $effected_id, $str, $str2, $showlevel, $style, $currentlevel + 1, TRUE );
				} elseif ($showlevel > 0 && $showlevel == $currentlevel) {
					$this->str .= $placeholder;
				}
			} else {
				eval ( "\$nstr = \"$str\";" );
				$this->str .= $nstr;
			}
			$this->str .= $recursion ? '</li></ul>' : '</li>';
		}
		if (! $recursion) {
			$this->str .= '</ul>';
		}
		return $this->str;
	}
	
	/**
	 * 获取子栏目json
	 * Enter description here ...
	 * @param unknown_type $myid
	 */
	public function creat_sub_json($myid, $str = '') {
		$sub_cats = $this->get_child ( $myid );
		$n = 0;
		if (is_array ( $sub_cats ))
			foreach ( $sub_cats as $c ) {
				$data [$n] ['id'] = iconv ( CHARSET, 'utf-8', $c ['catid'] );
				if ($this->get_child ( $c ['catid'] )) {
					$data [$n] ['liclass'] = 'hasChildren';
					$data [$n] ['children'] = array (array ('text' => '&nbsp;', 'classes' => 'placeholder' ) );
					$data [$n] ['classes'] = 'folder';
					$data [$n] ['text'] = iconv ( CHARSET, 'utf-8', $c ['catname'] );
				} else {
					if ($str) {
						@extract ( array_iconv ( $c, CHARSET, 'utf-8' ) );
						eval ( "\$data[$n]['text'] = \"$str\";" );
					} else {
						$data [$n] ['text'] = iconv ( CHARSET, 'utf-8', $c ['catname'] );
					}
				}
				$n ++;
			}
		return json_encode ( $data );
	}
	
	private function have($list, $item) {
		return (strpos ( ',,' . $list . ',', ',' . $item . ',' ));
	}
	
	/**
	 * 获取导航
	 * @access public
	 * @param int $bid 指定要调用显示的导航id，默认为0则调用所有
	 * @param int $maxlevel 指定栏目调用层次
	 * @param string $effected_id 导航ul的id样式值
	 * @param string $style 导航ul的class样式值
	 * @param string $homefont 用户给定的导航‘网站首页/首页’中文类似值
	 * @param boolean $recursion 是否是递归
	 * @param array $child 用于递归时,直接给定栏目数组
	 * @param string $enhomefont 用户给定的导航‘Website’英文类似值
	 * @param bool $bootstrap bootstrap模式导航
	 * @param bool $thumb 是否显示栏目图片
	 */
	public function get_nav($bid, $maxlevel, $effected_id = 'navlist', $style = 'filetree ', $homefont = '', $recursion = false, $child = '', $enhomefont = '', $bootstrap = false, $catthumb = false) {
		// 首页的英文描述,若指定,所有栏目都会显示其英文描述
		$indexen = '';
		if ($enhomefont) {
			$indexen = '<em>' . $enhomefont . '</em>';
		}
		// "首页"显示字样
		if ($homefont) {
			// 首页高亮
			$homeactive = (MODULE_NAME == 'Content' && CONTROLLER_NAME == 'Index' && ACTION_NAME == 'index') ? ' class="active"' : '';
			$homefont = '<li id="' . $effected_id . '_0"' . $homeactive . '><span class="fl_ico"></span><a href="' . URL () . '" title="' . $homefont . '"><span class="fl">' . $homefont . '</span>' . $indexen . '</a></li>';
		}
		// 获取当前栏目id
		$catid = isset ( $_GET ['catid'] ) && $_GET ['catid'] ? $_GET ['catid'] : 0;
		// ul 的id样式
		$effected = $effected_id ? ' id="' . $effected_id . '"' : '';
		// ul 的class样式
		$class = $style ? ' class="' . $style . '"' : '';
		// 第一个
		$number = 1;
		// 若不存在,取出指定bid的下级,若bid为0,则取出所有顶级栏目,也就是parentid为0的栏目.
		if (! $child) {
			$child = $this->get_child ( $bid );
		}
		// 统计一级栏目个数
		$total = count ( $child );
		// 非递归的时候,给定整个导航的开头
		if (! $recursion) {
			$this->ret .= '<ul' . $effected . $class . '>' . $homefont;
		}
		/* 栏目循环 */
		foreach ( $child as $id => $a ) {
			extract ( $a );
			// 如果是当前目录,或者是其子级目录,则此目录设为选中
			$arrchild = explode ( ',', $a ['arrchildid'] );
			$catactive = '';
			if (! empty ( $catid )) {
				$catactive = ($catid == $a ['id']) || (in_array ( $catid, $arrchild )) ? ' active' : '';
			}
			// 新窗口打开
			$target = ! empty ( $a ['istarget'] ) ? ' target="_blank" ' : '';
			// 栏目图片
			$image = $catthumb ? '<img src="' . $a ['thumb'] . '">' : '';
			// 设置层级
			if (! isset ( $this->level ) || ! $this->level) {
				$this->level = $a ['level'] ? $a ['level'] + $maxlevel - 1 : $maxlevel;
			}
			// 是否有子级栏目
			$ischild = $this->get_child ( $id );
			// 文件类型，有子id则显示为文件夹，反之为文件
			$foldertype = $ischild ? 'folder' : 'file';
			// 文件夹的id
			$folder_status = ' id="' . $effected_id . '_' . $id . '"';
			// bootstrap导航的的下拉样式
			$folder_style = $bootstrap ? ' dropdown' : '';
			// 当前层级的第一个栏目,给定样式first
			$first = $number == 1 ? 'first ' : '';
			// 当前层级的最后一个栏目,给定样式foot
			$folder_status .= $number == $total ? ' class="foot ' . $foldertype . $catactive . ($ischild ? $folder_style : '') . '"' : ' class="' . $first . $foldertype . $catactive . ($ischild ? $folder_style : '') . '"';
			$this->ret .= $recursion ? ($bootstrap ? '<ul class="dropdown-menu"><li' . $folder_status . '>' : '<ul><li' . $folder_status . '>') : '<li' . $folder_status . '>';
			$recursion = FALSE;
			// 是否显示英文描述
			$enzm = '';
			if ($enhomefont) {
				$enzm = $a ['enname'] ? '<em>' . $a ['enname'] . '</em>' : '<em>' . $a ['catdir'] . '</em>';
			}
			// 当前栏目存在子级,并且目录层级小于当前层级限制时进入
			if ($ischild && $a ['level'] < $this->level) {
				if ($bootstrap) {
					// bootstrap导航只支持2级
					$this->ret .= '<span class="fd_ico">' . $image . '</span><a rel="' . $a ['url'] . '" href="' . $a ['url'] . '" ' . $target . ' title="' . $a ['catname'] . '" class="dropdown-toggle" data-toggle="dropdown"><span class="fd">' . $a ['catname'] . '</span>' . $enzm . '</a>';
					$this->get_nav ( $id, 2, $effected_id, $style, '', TRUE, $ischild, $enhomefont, 1, $catthumb );
				} else {
					$this->ret .= '<span class="fd_ico">' . $image . '</span><a rel="' . $a ['url'] . '" href="' . $a ['url'] . '" ' . $target . ' title="' . $a ['catname'] . '"><span class="fd">' . $a ['catname'] . '</span>' . $enzm . '</a>';
					$this->get_nav ( $id, $maxlevel, $effected_id, $style, '', TRUE, $ischild, $enhomefont, $bootstrap, $catthumb );
				}
			} else {
				$this->ret .= '<span class="fl_ico">' . $image . '</span><a rel="' . $a ['url'] . '" href="' . $a ['url'] . '" ' . $target . ' title="' . $a ['catname'] . '"><span class="fl">' . $a ['catname'] . '</span>' . $enzm . '</a>';
			}
			// 结尾拼接
			$this->ret .= $recursion ? '</li></ul>' : '</li>';
			$number ++;
		}
		if (! $recursion) {
			$this->ret .= '</ul>';
		}
		return $this->ret;
	}
	
	/**
	 * 把返回的数据集转换成Tree
	 * @param array $list
	 * @param string $pk
	 * @param string $pid
	 * @param string $child
	 * @param int $root
	 */
	public function list_to_tree($list, $pk = 'id', $pid = 'parentid', $child = 'child', $root = 0){
		//创建树
		$tree = array ();
		if (is_array ( $list )) {
			$refer = array (); //创建基于主键的数组引用
			foreach ( $list as $key => $data ) {
				$refer [$data [$pk]] = & $list [$key];
			}
			foreach ( $list as $key => $data ) {
				//判断是否存在parent
				$parentId = $data [$pid];
				if ($root == $parentId) {
					$tree [] = & $list [$key];
				} else {
					if (isset ( $refer [$parentId] )) {
						$parent = & $refer [$parentId];
						$parent [$child] [] = & $list [$key];
					}
				}
			}
		}
		return $tree;
	}
}